using TerritoryGame.Application.Interfaces;
using TerritoryGame.Application.Dtos;
using TerritoryGame.Domain.Entities.App;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;

namespace TerritoryGame.Application.Services
{
    public class AppGameService : IAppGameService
    {
        private readonly ILogger<AppGameService> _logger;
        
        // 内存存储（生产环境应该使用Redis或数据库）
        private static readonly ConcurrentDictionary<string, GameRoom> _rooms = new();
        private static readonly ConcurrentDictionary<string, Player> _players = new();
        private static readonly ConcurrentDictionary<string, List<PaintAction>> _paintActions = new();

        public AppGameService(ILogger<AppGameService> logger)
        {
            _logger = logger;
        }

        public async Task<GameRoom> CreateRoomAsync(string roomName, int maxPlayers, int gameDuration, Player creator)
        {
            try
            {
                var room = new GameRoom
                {
                    RoomName = roomName,
                    MaxPlayers = maxPlayers,
                    GameDuration = gameDuration,
                    Status = GameStatus.Waiting,
                    Creator = creator,
                    Players = new List<Player> { creator },
                    CreatedAt = DateTime.UtcNow
                };

                // 为创建者分配颜色
                creator.Color = GeneratePlayerColor(room.Players);

                // 存储房间和玩家
                _rooms.TryAdd(room.Id.ToString(), room);
                _players.TryAdd(creator.Id.ToString(), creator);
                _paintActions.TryAdd(room.Id.ToString(), new List<PaintAction>());

                _logger.LogInformation("Room created: {RoomId} by {CreatorName}", room.Id, creator.Username);

                return await Task.FromResult(room);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to create room: {RoomName}", roomName);
                throw;
            }
        }

        public async Task<GameRoom?> GetRoomAsync(string roomId)
        {
            try
            {
                _rooms.TryGetValue(roomId, out var room);
                return await Task.FromResult(room);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get room: {RoomId}", roomId);
                return null;
            }
        }

        public async Task<bool> JoinRoomAsync(string roomId, Player player)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    return false;
                }

                // 检查房间状态和容量
                if (room.Status != GameStatus.Waiting || room.Players.Count >= room.MaxPlayers)
                {
                    return false;
                }

                // 检查玩家是否已在房间中
                if (room.Players.Any(p => p.Id.ToString() == player.Id.ToString()))
                {
                    return false;
                }

                // 为玩家分配颜色
                player.Color = GeneratePlayerColor(room.Players);

                // 添加玩家到房间
                room.Players.Add(player);
                _players.TryAdd(player.Id.ToString(), player);

                _logger.LogInformation("Player {PlayerName} joined room: {RoomId}", player.Username, roomId);

                return await Task.FromResult(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to join room: {RoomId} by {PlayerName}", roomId, player.Username);
                return false;
            }
        }

        public async Task<bool> LeaveRoomAsync(string roomId, string playerId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    return false;
                }

                var player = room.Players.FirstOrDefault(p => p.Id.ToString() == playerId);
                if (player == null)
                {
                    return false;
                }

                // 从房间移除玩家
                room.Players.Remove(player);
                _players.TryRemove(playerId, out _);

                // 如果房间空了，删除房间
                if (room.Players.Count == 0)
                {
                    _rooms.TryRemove(roomId, out _);
                    _paintActions.TryRemove(roomId, out _);
                }

                _logger.LogInformation("Player {PlayerName} left room: {RoomId}", player.Username, roomId);

                return await Task.FromResult(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to leave room: {RoomId} by {PlayerId}", roomId, playerId);
                return false;
            }
        }

        public async Task<bool> StartGameAsync(string roomId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    _logger.LogWarning("Room not found: {RoomId}", roomId);
                    return false;
                }

                _logger.LogInformation("Attempting to start game in room: {RoomId}, Status: {Status}, Players: {PlayerCount}", 
                    roomId, room.Status, room.Players.Count);

                // 检查游戏是否可以开始
                // 房间状态必须是 Waiting 或 Ready，且至少要有1个玩家
                if ((room.Status != GameStatus.Waiting && room.Status != GameStatus.Ready) || room.Players.Count < 1)
                {
                    _logger.LogWarning("Cannot start game: Status={Status}, Players={PlayerCount}", 
                        room.Status, room.Players.Count);
                    return false;
                }

                // 开始游戏
                room.Status = GameStatus.Playing;
                room.StartTime = DateTime.UtcNow;

                // 重置所有玩家面积
                foreach (var player in room.Players)
                {
                    player.AreaCount = 0;
                }

                _logger.LogInformation("Game started successfully in room: {RoomId}", roomId);

                return await Task.FromResult(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to start game in room: {RoomId}", roomId);
                return false;
            }
        }

        /// <summary>
        /// 设置房间为准备就绪状态（已进入游戏界面）
        /// </summary>
        public async Task<bool> SetRoomReadyAsync(string roomId)
        {
            try
            {
                _logger.LogInformation("Attempting to set room ready: {RoomId}", roomId);
                
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    _logger.LogWarning("Room not found in memory: {RoomId}", roomId);
                    return false;
                }

                _logger.LogInformation("Room found, current status: {Status}, players count: {PlayerCount}", 
                    room.Status, room.Players.Count);

                // 只有等待中的房间可以设置为准备就绪
                if (room.Status != GameStatus.Waiting)
                {
                    _logger.LogWarning("Room status is not Waiting: {Status}, cannot set to Ready", room.Status);
                    return false;
                }

                // 设置房间为准备就绪状态
                room.Status = GameStatus.Ready;

                _logger.LogInformation("Room set to ready successfully: {RoomId}", roomId);

                return await Task.FromResult(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to set room ready: {RoomId}", roomId);
                return false;
            }
        }

        public async Task<bool> EndGameAsync(string roomId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    return false;
                }

                room.Status = GameStatus.Finished;
                room.EndTime = DateTime.UtcNow;

                _logger.LogInformation("Game ended in room: {RoomId}", roomId);

                return await Task.FromResult(true);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to end game in room: {RoomId}", roomId);
                return false;
            }
        }

        public async Task<PaintAction> RecordPaintActionAsync(PaintAction paintAction)
        {
            try
            {
                paintAction.CreatedAt = DateTime.UtcNow;

                // 存储涂色动作
                if (_paintActions.TryGetValue(paintAction.RoomId.ToString(), out var actions))
                {
                    actions.Add(paintAction);
                }

                // 更新玩家面积
                if (_players.TryGetValue(paintAction.PlayerId.ToString(), out var player))
                {
                    if (paintAction.Tool == "brush")
                    {
                        player.AreaCount += 1;
                    }
                    else if (paintAction.Tool == "eraser")
                    {
                        player.AreaCount = Math.Max(0, player.AreaCount - 1);
                    }
                }

                _logger.LogDebug("Paint action recorded: {PlayerId} at ({X}, {Y})", 
                    paintAction.PlayerId, paintAction.X, paintAction.Y);

                return await Task.FromResult(paintAction);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to record paint action for player: {PlayerId}", paintAction.PlayerId);
                throw;
            }
        }

        public async Task<List<Player>> GetRoomPlayersAsync(string roomId)
        {
            try
            {
                if (_rooms.TryGetValue(roomId, out var room))
                {
                    return await Task.FromResult(room.Players);
                }
                return await Task.FromResult(new List<Player>());
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get room players: {RoomId}", roomId);
                return new List<Player>();
            }
        }

        public async Task<Player?> GetPlayerAsync(string playerId)
        {
            try
            {
                _players.TryGetValue(playerId, out var player);
                return await Task.FromResult(player);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get player: {PlayerId}", playerId);
                return null;
            }
        }

        public async Task<bool> UpdatePlayerAreaAsync(string playerId, int area)
        {
            try
            {
                if (_players.TryGetValue(playerId, out var player))
                {
                    player.AreaCount = Math.Max(0, area);
                    return await Task.FromResult(true);
                }
                return await Task.FromResult(false);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to update player area: {PlayerId}", playerId);
                return false;
            }
        }

        public async Task<List<GameRoom>> GetActiveRoomsAsync()
        {
            try
            {
                var activeRooms = _rooms.Values
                    .Where(r => r.Status != GameStatus.Finished)
                    .OrderByDescending(r => r.CreatedAt)
                    .ToList();

                return await Task.FromResult(activeRooms);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get active rooms");
                return new List<GameRoom>();
            }
        }

        public async Task<bool> DeleteRoomAsync(string roomId)
        {
            try
            {
                if (_rooms.TryRemove(roomId, out var room))
                {
                    // 移除所有玩家
                    foreach (var player in room.Players)
                    {
                        _players.TryRemove(player.Id.ToString(), out _);
                    }

                    // 移除涂色动作
                    _paintActions.TryRemove(roomId, out _);

                    _logger.LogInformation("Room deleted: {RoomId}", room.Id);
                    return await Task.FromResult(true);
                }
                return await Task.FromResult(false);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to delete room: {RoomId}", roomId);
                return false;
            }
        }

        public async Task<GameResult> CalculateGameResultAsync(string roomId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    throw new InvalidOperationException($"Room {roomId} not found");
                }

                var players = room.Players.OrderByDescending(p => p.AreaCount).ToList();
                var winner = players.FirstOrDefault();
                var totalArea = players.Sum(p => p.AreaCount);
                var gameDuration = room.StartTime.HasValue 
                    ? (int)(DateTime.UtcNow - room.StartTime.Value).TotalMinutes 
                    : 0;

                // Convert Player entities to PlayerInfo DTOs
                var playerInfos = players.Select(p => new PlayerInfo
                {
                    Id = p.Id,
                    Username = p.Username,
                    Color = p.Color,
                    AreaCount = p.AreaCount
                }).ToList();

                var winnerInfo = winner != null ? new PlayerInfo
                {
                    Id = winner.Id,
                    Username = winner.Username,
                    Color = winner.Color,
                    AreaCount = winner.AreaCount
                } : null;

                var result = new GameResult
                {
                    RoomId = roomId,
                    Winner = winnerInfo,
                    Rankings = playerInfos,
                    TotalArea = totalArea,
                    GameDuration = gameDuration,
                    EndTime = DateTime.UtcNow
                };

                _logger.LogInformation("Game result calculated for room: {RoomId}, Winner: {Winner}",
                    roomId, winner?.Username ?? "None");

                return await Task.FromResult(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to calculate game result for room: {RoomId}", roomId);
                throw;
            }
        }

        private string GeneratePlayerColor(List<Player> existingPlayers)
        {
            var colors = new[]
            {
                "#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7",
                "#DDA0DD", "#98D8C8", "#F7DC6F", "#BB8FCE", "#85C1E9"
            };

            var usedColors = existingPlayers.Select(p => p.Color).ToHashSet();
            var availableColors = colors.Where(c => !usedColors.Contains(c)).ToArray();

            if (availableColors.Length > 0)
            {
                return availableColors[new Random().Next(availableColors.Length)];
            }

            // 如果没有可用颜色，生成随机颜色
            return $"#{new Random().Next(0x1000000):X6}";
        }

        // 新增方法实现
        public async Task<GameRoom> CreateRoomAsync(string creatorId, string roomName, int maxPlayers, int gameDuration)
        {
            try
            {
                // 首先尝试从现有玩家中查找
                var creator = await GetPlayerAsync(creatorId);
                
                // 如果找不到玩家，创建一个新的玩家对象
                if (creator == null)
                {
                    // 这里应该从用户服务获取用户信息，然后创建对应的玩家
                    // 暂时创建一个基本的玩家对象
                    creator = new Player
                    {
                        Id = Guid.Parse(creatorId),
                        Username = $"User_{creatorId.Substring(0, 8)}", // 临时用户名
                        Color = "#FF6B6B", // 默认颜色
                        AreaCount = 0,
                        IsOnline = true,
                        LastSeen = DateTime.UtcNow
                    };
                    
                    // 将新创建的玩家添加到内存存储中
                    _players.TryAdd(creator.Id.ToString(), creator);
                }

                return await CreateRoomAsync(roomName, maxPlayers, gameDuration, creator);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to create room: {RoomName} by {CreatorId}", roomName, creatorId);
                throw;
            }
        }

        public async Task<bool> JoinRoomAsync(string roomId, string playerId)
        {
            try
            {
                // 首先检查房间是否存在
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    _logger.LogWarning("Room {RoomId} not found when trying to join", roomId);
                    return false;
                }

                // 检查房间状态
                if (room.Status != GameStatus.Waiting)
                {
                    _logger.LogWarning("Cannot join room {RoomId} - status is {Status}, not Waiting", roomId, room.Status);
                    return false;
                }

                // 检查房间是否已满
                if (room.Players.Count >= room.MaxPlayers)
                {
                    _logger.LogWarning("Cannot join room {RoomId} - room is full ({CurrentPlayers}/{MaxPlayers})", 
                        roomId, room.Players.Count, room.MaxPlayers);
                    return false;
                }

                // 检查玩家是否已在房间中
                if (room.Players.Any(p => p.Id.ToString() == playerId))
                {
                    _logger.LogWarning("Player {PlayerId} is already in room {RoomId}", playerId, roomId);
                    return false;
                }

                var player = await GetPlayerAsync(playerId);
                if (player == null)
                {
                    // 如果找不到玩家，创建一个新的玩家对象
                    player = new Player
                    {
                        Id = Guid.Parse(playerId),
                        Username = $"User_{playerId.Substring(0, 8)}", // 临时用户名
                        Color = "#4ECDC4", // 默认颜色
                        AreaCount = 0,
                        IsOnline = true,
                        LastSeen = DateTime.UtcNow
                    };
                    
                    // 将新创建的玩家添加到内存存储中
                    _players.TryAdd(player.Id.ToString(), player);
                }

                return await JoinRoomAsync(roomId, player);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to join room: {RoomId} by {PlayerId}", roomId, playerId);
                return false;
            }
        }

        public async Task<bool> StartGameAsync(string roomId, string userId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    return false;
                }

                // 检查用户是否是房间创建者
                if (room.Creator?.Id.ToString() != userId)
                {
                    return false;
                }

                return await StartGameAsync(roomId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to start game: {RoomId} by {UserId}", roomId, userId);
                return false;
            }
        }

        public async Task<bool> EndGameAsync(string roomId, string userId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    return false;
                }

                // 检查用户是否是房间创建者
                if (room.Creator?.Id.ToString() != userId)
                {
                    return false;
                }

                return await EndGameAsync(roomId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to end game: {RoomId} by {UserId}", roomId, userId);
                return false;
            }
        }

        public async Task<List<RoomLeaderboardEntry>> GetRoomLeaderboardAsync(string roomId)
        {
            try
            {
                if (!_rooms.TryGetValue(roomId, out var room))
                {
                    return new List<RoomLeaderboardEntry>();
                }

                var leaderboard = room.Players
                    .OrderByDescending(p => p.AreaCount)
                    .Select((player, index) => new RoomLeaderboardEntry
                    {
                        PlayerId = player.Id,
                        Score = player.AreaCount,
                        Rank = index + 1
                    })
                    .ToList();

                return await Task.FromResult(leaderboard);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get room leaderboard: {RoomId}", roomId);
                return new List<RoomLeaderboardEntry>();
            }
        }
    }
}
